package com.easystudy.interceptor;

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;

import org.apache.tomcat.util.http.MimeHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.easystudy.anno.LoginRequired;
import com.easystudy.config.AuthConfig;
import com.easystudy.util.TokenUtil;

/**
 * @文件名称: AuthInterceptor.java
 * @功能描述: 客户端模式授权拦截器 
 * @版权信息：  www.easystudy.com
 * @技术交流：  961179337(QQ群)
 * @编写作者：  lixx2048@163.com
 * @联系方式：  941415509(QQ)
 * @开发日期：  2020年8月17日
 * @历史版本： V1.0 
 * @备注信息：
 */
@Configuration
public class AuthInterceptor extends HandlerInterceptorAdapter {
	@Autowired
	private AuthConfig config;
	@Resource
	private TokenUtil tokenUtil;

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		// 拦截处理代码
		HandlerMethod method = (HandlerMethod) handler;
		LoginRequired loginRequired = method.getMethodAnnotation(LoginRequired.class);

		// 需要拦截的方法
		if (null == loginRequired) {
			return true;
		}
		
		// 通过客户端模式换取token
		String bearerToken = tokenUtil.getBearerTokenByClientCredentials(config.getClientId(), config.getClientSecret(), config.getAccessTokenUri());
		if (StringUtils.isEmpty(bearerToken)) {
			return false;
		}
		
		// 添加权限头
		try {
			addRequestHeader(request, "Authorization", bearerToken);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return false;
	}

	private void addRequestHeader(HttpServletRequest request, String key, String value) throws Exception{
		// 获取HttpServletRequest类类
		Class<? extends HttpServletRequest> requestClass = request.getClass();
		Field request1 = requestClass.getDeclaredField("request");
		request1.setAccessible(true);
		
		// 获取HttpServletRequest对象值
		Object o = request1.get(request);
		Field coyoteRequest = o.getClass().getDeclaredField("coyoteRequest");
		coyoteRequest.setAccessible(true);
		
		// 获取headers属性
		Object o1 = coyoteRequest.get(o);
		Field headers = o1.getClass().getDeclaredField("headers");
		headers.setAccessible(true);
		
		// 添加自定义属性
		MimeHeaders o2 = (MimeHeaders) headers.get(o1);
		o2.addValue("Authorization").setString(value);					
	}

	/**
	 * @文件名称: AuthInterceptor.java
	 * @功能描述: 扩展HttpServletRequest：可修改请求头
	 * @版权信息：  www.easystudy.com
	 * @技术交流：  961179337(QQ群)
	 * @编写作者：  lixx2048@163.com
	 * @联系方式：  941415509(QQ)
	 * @开发日期：  2020年8月17日
	 * @历史版本： V1.0 
	 * @备注信息：
	 */
	public final class MutableHttpServletRequest extends HttpServletRequestWrapper {
		// 自定义头存放
		private final Map<String, String> customHeaders;

		public MutableHttpServletRequest(HttpServletRequest request) {
			super(request);
			this.customHeaders = new HashMap<>();
		}

		/**
		 * @功能描述: 往header中添加参数
		 * @版权信息：  www.easystudy.com
		 * @编写作者：  lixx2048@163.com
		 * @开发日期：  2020年8月17日
		 * @备注信息：
		 */
		public void putHeader(String key, String value) {
			this.customHeaders.put(key, value);
		}

		@Override
		public String getHeader(String key) {
			// 先从本地获取
			String headerValue = customHeaders.get(key);
			if (headerValue != null) {
				return headerValue;
			}
			// 在从request中获取
			return ((HttpServletRequest) getRequest()).getHeader(key);
		}

		/**
		 * @功能描述: 头部枚举器
		 * @版权信息：  www.easystudy.com
		 * @编写作者：  lixx2048@163.com
		 * @开发日期：  2020年8月17日
		 * @备注信息：
		 */
		@Override
		public Enumeration<String> getHeaderNames() {
			// 遍历头部参数添加到自定义集合中
			Set<String> set = new HashSet<>(customHeaders.keySet());
			Enumeration<String> e = ((HttpServletRequest) getRequest()).getHeaderNames();
			while (e.hasMoreElements()) {
				String n = e.nextElement();
				set.add(n);
			}
			// 集合转枚举器
			return Collections.enumeration(set);
		}

	}
}
